package top.huhuiyu.springboot3.exception;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import top.huhuiyu.springboot3.base.R;

import java.sql.SQLException;
import java.util.List;

/**
 * 异常统一处理
 *
 * @author 胡辉煜
 */
@ControllerAdvice
public class AppExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(AppExceptionHandler.class);

    /**
     * 自定义异常处理
     *
     * @param ex 异常信息
     * @return 自定义应答结果
     */
    @ExceptionHandler({AppException.class})
    @ResponseBody
    public R<String> handler(AppException ex) {
        logger.debug("自定义异常：{}", ex.getMessage());
        return R.fail(ex.getMessage());
    }

    /**
     * 校验错误处理
     *
     * @param ex 异常信息
     * @return 标准应答结果
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public R<String> handler(MethodArgumentNotValidException ex) {
        logger.debug("校验异常：{}", ex.getMessage());
        String errorInfo = buildErrorInfo(ex.getAllErrors());
        return R.fail(501, errorInfo);
    }

    /**
     * 数据绑定校验错误处理
     *
     * @param ex 异常信息
     * @return 标准应答结果
     */
    @ExceptionHandler(BindException.class)
    @ResponseBody
    public R<String> handler(BindException ex) {
        logger.debug("数据绑定校验异常：{}", ex.getMessage());
        String errorInfo = buildErrorInfo(ex.getAllErrors());
        return R.fail(502, errorInfo);
    }

    /**
     * 构造校验错误信息
     *
     * @param errors 校验错误列表
     * @return 校验错误信息
     */
    private static String buildErrorInfo(List<ObjectError> errors) {
        // 拼接错误信息
        StringBuilder sb = new StringBuilder();
        for (ObjectError oe : errors) {
            sb.append(oe.getDefaultMessage()).append(",");
        }
        if (!sb.isEmpty()) {
            sb.deleteCharAt(sb.length() - 1);
        }
        return sb.toString();
    }

    /**
     * 数据库操作异常处理
     *
     * @param ex 异常信息
     * @return 标准应答结果
     */
    @ExceptionHandler({DataAccessException.class})
    @ResponseBody
    public R<String> handler(DataAccessException ex) {
        logger.error(String.format("数据库操作异常%s", ex.getMessage()), ex);
        return R.fail(520, "数据信息异常，请联系网站管理员");
    }

    /**
     * 数据库异常处理
     *
     * @param ex 异常信息
     * @return 标准应答结果
     */
    @ExceptionHandler({SQLException.class})
    @ResponseBody
    public R<String> handler(SQLException ex) {
        logger.error(String.format("sql异常%s", ex.getMessage()), ex);
        return R.fail(521, "数据处理发生异常");
    }

    /**
     * 标准异常处理
     *
     * @param ex 异常信息
     * @return 标准应答结果
     */
    @ExceptionHandler({Exception.class})
    @ResponseBody
    public R<String> handler(Exception ex) {
        logger.error("系统异常", ex);
        return R.fail(ex.getMessage());
    }
}
